#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>

#include "debug.h"
#include "environ.h"
#include "record.h"
#include "sdmng.h"
#include "cbz_source.h"
#include "avi_sink.h"
#include "mav_sink.h"
#include "cbz_framework.h"
#include "exception.h"
#include "content.h"
#include "event.h"
#include "net_usr.h"
#include "live.h"
#include "media.h"
#include "rsc_adapter.h"
#include "mav_db.h"

#define RECORD_VIDEO_STREAM_CHN 1 // 0 - 720p,1 - VGA, 2 - CIF

static struct storage_dev_meta sd_meta = 
{
    .dev_type = DEV_SD_TYPE,
    .dev_subtype = DEV_SUB_SDIO,
    .fs_type = FS_VFAT,
    .max_num = 1,
    .prev_devid = 0,
    .mpoint = "/mnt",

    .filter = cont_filter,
    .delter = cont_delter,
};

static struct rsc_record_param rec_param = 
{
    .media = 
    { /* caculate record file size by bitrate */
	.video_cbr = 1,
	.video_bitrate = 512*1024,
	.video_framerate = 10,
	.video_gop = 10,
	.video_codec = REC_CODEC_H264,
	.video_width = 640,
	.video_height = 480,
	.pic_level = 5,

	.audio_sample_fmt = REC_SAMPLE_FMT_S16,
	.audio_sample_rate = 8000,
	.audio_channels = 1,
	.audio_bitrate = 64000,
	.audio_codec = REC_CODEC_G711A,
    },
    .control = 
    {
	.on = 1,
	.file_time = 30*60,
	.file_pack = REC_PACK_MAV,
	.file_format = "YYYYMMDD/hhmmss_nn.mav",
	.audio_on = 1, 
	.audio_solo = REC_AUDIO_SOLO_OFF,
	.chn_suffix_start = -1,
	.audio_time = 0, 
	.audio_pack = REC_PACK_MAV, //REC_PACK_RAW
	.chn_temp = 1,
	.mode = REC_MODE_AUTO,
	.mode_desc = "auto",
    },
    .source = 
    {
	.chn = 1,
	.parallel = 0,// not used now
	.video_ds = {NULL},
	.audio_ds = {NULL},
	.meta_ds = {NULL},
	.preprocess = {cbz_video_preprocess,cbz_audio_preprocess,NULL},
	.postprocess = {NULL},
    },
    .sink = 
    {
	.init_sink = mav_init_sink,
	.fill_sink = mav_fill_sink,
	.exit_sink = mav_exit_sink,
    }
};

int rsc_update_media_param(void *venc)
{
    if(venc==NULL)
    {
	SLOG(ERR,"venc is null!\n");
	return -1;
    }
    /// convert params
    int ret = 0;
    struct rsc_record_param rec_param;

    memset(&rec_param,0,sizeof(rec_param));
    ret = rsc_get_rec_params(&rec_param);
    if(ret < 0)
    {
	SLOG(PRI,"rsc_get_rec_params fail!\n");
	return -1;
    }
    struct video_venc_param *venc_attr = (struct video_venc_param*)venc;
    rec_param.media.video_cbr = venc_attr->cbr==1?1:0;
    rec_param.media.video_bitrate = venc_attr->brate*1024;
    printf("---rsc media brate = %d\n",rec_param.media.video_bitrate);
    rec_param.media.video_framerate = venc_attr->frate;
    rec_param.media.video_gop = venc_attr->gop;
    switch(venc_attr->resolution)
    {
	case VIDEO_PIC_QVGA:
	    rec_param.media.video_width = 352;
	    rec_param.media.video_height= 288;
	    break;
	case VIDEO_PIC_VGA:
	    rec_param.media.video_width = 640;
	    rec_param.media.video_height= 480;
	    break;
	case VIDEO_PIC_HD720:
	    rec_param.media.video_width = 1280;
	    rec_param.media.video_height= 720;
	    break;
    }

    ret = rsc_set_rec_params(&rec_param);
    if(ret < 0)
    {
	SLOG(PRI,"rsc_set_rec_params fail!\n");
	return -1;
    }
    return 0;
}

static int rsc_update_rec_param(void)
{
    struct rsc_record_param rec_param;
    struct alarm_param alarm_rec;
    int ret = 0;

    memset(&rec_param,0,sizeof(rec_param));
    memset (&alarm_rec, 0, sizeof (alarm_rec));
    ret = rsc_get_rec_params(&rec_param);
    if(ret < 0)
    {
	SLOG(ERR,"rsc_get_rec_params fail!\n");
	return -1;
    }
    if(event_get_alarm_param (&alarm_rec)<0)
    {
	SLOG(ERR,"event_get_alarm_param fail!\n");
	return -1;
    }
    if(!alarm_rec.record.on && !rec_param.control.on)
    {
	rec_param.control.on = 1;
	rec_param.control.audio_on = 1;
	ret = rsc_set_rec_params(&rec_param);
	PLOG(PRI,"set record config ret = %d\n",ret);
    }
    else if(alarm_rec.record.on && rec_param.control.on)
    {
	rec_param.control.on = 0;
	rec_param.control.audio_on = 1;
	ret = rsc_set_rec_params(&rec_param);
	PLOG(PRI,"set record config ret = %d\n",ret);
    }
    return 0;
}

int rsc_process_alarm(int tlen)
{
    if(tlen < 0)
    {
	SLOG(ERR,"alaram record time len [%d] invalid!\n",tlen);
	return -1;
    }
    if(!rsc_get_record())
    {
	SLOG(WRN,"RSC component is not prepared!\n");
	return -1;
    }
    if(is_record())
    {
	SLOG(WRN,"record is processing!\n");
	return -1;
    }
    struct rsc_channel_param alarm_param;
    memset(&alarm_param,0,sizeof(alarm_param));
    alarm_param.chn = 0; // get channel 0 parameter
    if(rsc_get_chn_params(&alarm_param)<0)
    {
	SLOG(ERR,"rsc_get_chn_params fail!\n");
	return -1;
    }
    alarm_param.control.on = 1;
    alarm_param.control.audio_on = 1;
    alarm_param.control.file_time = tlen;
    alarm_param.control.mode = REC_MODE_EVENT;
    strcpy(alarm_param.control.mode_desc,"event");// less than 16bytes is required
    strcpy(alarm_param.control.mode_param.event_desc,"alarm");
    alarm_param.control.mode_param.event_time = tlen;
    alarm_param.control.mode_param.event_trigger = 1;
    if(rsc_set_chn_params(&alarm_param)<0)
    {
	SLOG(ERR,"rsc_set_chn_params fail!\n");
	return -1;
    }
    return	rsc_start_record(0);
}

int rsc_process_init(void)
{
    int ret = 0, prev_id = 0;
    char mpoint[64]={0};

    ret = rsc_init_storage(&sd_meta);
    if(ret < 0)
    {
	SLOG(ERR,"rsc_init_storage err,ret = %d\n",ret);
	return -1;
    }
    prev_id = rsc_exception_init(NULL,sd_meta.max_num,mpoint);
    if(prev_id>=0)
	rsc_set_prev_devid(prev_id);

    /** fill record parameters */
    /// data source config
    int i = 0,chns = rec_param.source.chn;
    for(i=0;i<chns;i++)
    {// only one channel is used
	rec_param.source.video_ds[i] = (unsigned char *)net_usr[RECORD_USER_ID].cbz1;
	rec_param.source.audio_ds[i] = (unsigned char *)net_usr[RECORD_USER_ID].cbz1;
	rec_param.source.audio_ds[i+chns] = NULL;
	rec_param.source.meta_ds[i] = NULL;
    }
    if(rsc_init_record(&rec_param)<0)
    {
	SLOG(ERR,"rsc_init_record failed!\n");
	return -1;
    }
    
    struct video_venc_param venc;
    if(media_get_venc_param(RECORD_VIDEO_STREAM_CHN,&venc)<0)
    {
	SLOG(ERR,"media_get_venc_param fail!\n");
    }
    else
	rsc_update_media_param(&venc);
    
    /** update rec param to mutex use alarm record / power-on record */
    rsc_update_rec_param();
    mav_db_init_list();

    SLOG(PRI,"rsc_process_init success!\n");
    return 0;
}

void *rsc_process_thread(void *arg)
{
    int rsc_rec = 0;
    int ret = 0;
    pthread_t storage_tid;

    char mpoint[64]={0};
    ret = pthread_create(&storage_tid,NULL,rsc_storage_process,NULL);
    if(ret)
    {
	SLOG(ERR,"create rsc_storage_process thread error:%s\n",strerror(ret));
	ret = -1;
	return (void*)ret;
    }

    while(runflag && rsc_get_avail_dev(0,mpoint)<0) 
	sleep(2);

    SLOG(PRI,">>>>>start to record process thread...\n");
    /* create record process threads */
    rsc_rec = rsc_handle_record();

    int record_usr_id = 0xff;
    while(runflag)
    {
	sleep(1);
	if(is_record())
	{
	    record_usr_id = req_record_usr(is_audio_record(),REQ_VGA);
	}
	else if(record_usr_id!=0xff)
	{
	    deconnect_usr(&net_usr[record_usr_id]);
	}
    }

    if(record_usr_id!=0xff)
	deconnect_usr(&net_usr[record_usr_id]);
    rsc_exit_record(rsc_rec);
    SLOG(PRI,"exit record ...\n");
    rsc_exit_storage();
    SLOG(PRI,"exit storage...\n");
    if(!ret)
	pthread_join(storage_tid,NULL);

    return (void*)ret;
}

int rsc_process_exit(void)
{
    mav_db_exit_list();
    return 0;
}

